#include "h265codec.hpp"
#include <iostream>
using namespace std;

H265Codec::H265Codec(int width, int height, AVPixelFormat fmt, bool isDecode) : width_(width),
height_(height), fmt_(fmt)
{
	if (isDecode) {
		codec_ = avcodec_find_decoder(codecId_);
	}
	else {
		codec_ = avcodec_find_encoder(codecId_);
	}
	if (!codec_) {
		std::runtime_error("avcodec_find failed");
	}
	ctx_ = avcodec_alloc_context3(codec_);
	if (!ctx_) {
		// cout << "avcodec_alloc_context3() failed" << endl;
		std::runtime_error("avcodec_alloc_context3() failed");
	}
	int ret = avcodec_open2(ctx_, nullptr, nullptr);
	if (ret != 0) {
		// cerr << "avcodec_open2() failed" << endl;
		std::runtime_error("avcodec_alloc_context3() failed");
	}
	pkt_ = av_packet_alloc();
	if (!pkt_) {
		std::runtime_error("av_packet_alloc");
	}
	// 锟斤拷锟斤拷墙锟斤拷耄琭rame锟斤拷data锟秸间不锟斤拷�?�锟皆硷拷锟斤拷锟斤�?
	frame_ = av_frame_alloc();
	if (!frame_) {
		runtime_error("av_frame_alloc");
	}
	// 锟斤拷�?�锟斤拷帧锟街革�?
	parser_ = av_parser_init(codecId_);
	if (!parser_) {
		std::runtime_error("av_parser_init");
	}
}

H265Codec::~H265Codec()
{
	// 锟斤拷源锟酵凤拷
	av_parser_close(parser_);
	av_frame_free(&frame_);
	av_packet_free(&pkt_);

	avcodec_free_context(&ctx_);
	avcodec_close(ctx_);
}

int H265Codec::decode(const unsigned char* buff, int len, unsigned char *outbuff, int linesize)
{
	if ( buff == nullptr || len <= 0) {
		return -1;
	}
	auto data = (const uint8_t*)buff;
	while (len > 0) {
		auto sz = av_parser_parse2(parser_, ctx_,
			// 锟斤拷锟斤拷锟斤拷锟斤拷
			&pkt_->data, &pkt_->size,
			// 锟斤拷锟斤拷
			data, len,
			AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0
		);
		data += sz;
		len -= sz;
		// �?锟斤拷锟斤拷锟斤拷锟轿猴拷锟斤拷锟斤�?
		if (pkt_->size <= 0) {
			break;
		}
		// cout << "packet size : " << pkt->size << endl;
		auto ret = avcodec_send_packet(ctx_, pkt_);
		if (ret < 0) {
			cerr << "avcodec_send_packet" << endl;
			break;
		}
		// 锟叫匡拷锟杰伙拷取锟斤拷锟斤拷帧锟斤拷锟斤拷
		while (ret >= 0) {
			ret = avcodec_receive_frame(ctx_, frame_);
			frame_->color_range = AVCOL_RANGE_JPEG;
			if (ret < 0) {
				break;
			}
			// 锟斤拷锟斤拷锟侥匡拷锟斤拷式一锟斤拷锟斤拷锟酵诧拷锟斤拷�?�转锟斤拷锟斤拷�?
			if (frame_->format == fmt_ && frame_->width == width_ && frame_->height == height_) {
				continue;
			}
			int hh = this->convertScale(outbuff, linesize);
			if (hh <= 0) {
				break;
			}
		}
	}
	return 0;
}

int H265Codec::convertScale(unsigned char* outbuff, int linesize)
{
	swsCtx_ = sws_getCachedContext(
		swsCtx_,
		frame_->width, frame_->height, AV_PIX_FMT_YUV420P,
		width_, height_, fmt_,
		SWS_BILINEAR,
		nullptr, nullptr, nullptr
	);
	// swsCtx_->frame = frame_;
	if (swsCtx_ == nullptr) {
		cerr << "swsCtx_  sws_getCachedContext" << endl;
		return -1;
	}
	unsigned char* data[1]{ (unsigned char*)outbuff };
	int ls[1]{ linesize };
	int h = sws_scale(
		swsCtx_,
		frame_->data, frame_->linesize, 0, frame_->height,
		data, ls
	);
	return h;
}
